package hu.plusone.fakecommander.flickr;

import com.flickr4java.flickr.Flickr;
import com.flickr4java.flickr.FlickrException;
import com.flickr4java.flickr.REST;
import com.flickr4java.flickr.RequestContext;
import com.flickr4java.flickr.auth.Auth;
import com.flickr4java.flickr.photos.Photo;
import com.flickr4java.flickr.photos.PhotoList;
import com.flickr4java.flickr.photos.Size;
import com.flickr4java.flickr.photosets.Photoset;
import com.flickr4java.flickr.uploader.UploadMetaData;
import hu.plusone.fakecommander.util.Utils;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.scribe.model.Token;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FlickrApiImpl implements FlickrApi {

    private static final Logger LOGGER = LoggerFactory.getLogger(FlickrApiImpl.class);
    private final Flickr api;
    private Auth auth;
    private static final String INDEX_FILE = "___index";
    private static final int ORIGINAL_SIZE = Size.ORIGINAL;

    public FlickrApiImpl() throws IOException, FlickrException {
        Properties properties = new Properties();
        properties.load(ClassLoader.getSystemResourceAsStream("settings.properties"));
        api = new Flickr(
          properties.getProperty(FlickrProperties.API_KEY.getProperty()),
          properties.getProperty(FlickrProperties.API_SECRET.getProperty()),
          new REST());
        api.getAuthInterface().checkToken(
          properties.getProperty(FlickrProperties.TOKEN.getProperty()),
          properties.getProperty(FlickrProperties.TOKEN_SECRET.getProperty()));
        initAuth(properties.getProperty(FlickrProperties.TOKEN.getProperty()),
          properties.getProperty(FlickrProperties.TOKEN_SECRET.getProperty()));
    }

    private void initAuth(String token, String tokenSecret) throws FlickrException {
        auth = api.getAuthInterface().checkToken(new Token(token, tokenSecret));
        RequestContext.getRequestContext().setAuth(auth);
    }

    private String getUserId() {
        return auth.getUser().getId();
    }

    @Override
    public String createSet(String setName) {
        LOGGER.info("createSet(" + setName + ")");
        try {
            Photoset photoset = findByName(setName);
            if (photoset != null) {
                return photoset.getId();
            }
            String photoId = upload(INDEX_FILE, Utils.generateRandomPictureData());
            photoset = api.getPhotosetsInterface().create(setName, setName, photoId);
            return photoset.getId();
        } catch (FlickrException ex) {
            throw new FlickrRuntimeException(ex);
        }
    }

    private String upload(String photoName, byte[] picData) throws FlickrException {
        UploadMetaData metaData = new UploadMetaData();
        metaData.setTitle(photoName);
        metaData.setDescription(photoName);
        metaData.setPublicFlag(true);
        return api.getUploader().upload(picData, metaData);
    }

    @Override
    public String update(String setName, String filename, byte[] data) {
        try {
            String photoId = upload(filename, data);
            addToPhotoset(setName, photoId);
            return photoId;
        } catch (FlickrException ex) {
            throw new FlickrRuntimeException(ex);
        }
    }

    private Photo findPhotoInSet(String setName, String photoName) throws FlickrException {
        LOGGER.info("findPhotoInSet(" + setName + ", " + photoName + ")");
        Photoset photoset = findByName(setName);
        if (photoset == null) {
            return null;
        }
        LOGGER.debug("setid: " + photoset.getId());
        LOGGER.debug("setname: " + photoset.getTitle());
        LOGGER.debug("setcount: " + photoset.getPhotoCount());
        
        PhotoList<Photo> photoList = api.getPhotosetsInterface().getPhotos(photoset.getId(), Integer.MAX_VALUE, 0);
        for (Photo photo : photoList) {
            if (photo.getTitle().equals(photoName)) {
                return photo;
            }
        }
        return null;
    }

    @Override
    public InputStream read(String setName, String photoName) {
        LOGGER.info("read(" + setName + ", " + photoName + ")");
        try {
            Photo photo = findPhotoInSet(setName, photoName);
            return api.getPhotosInterface().getImageAsStream(photo, ORIGINAL_SIZE);
        } catch (FlickrException ex) {
            throw new FlickrRuntimeException(ex);
        }
    }

    private Photoset findByName(String setName) throws FlickrException {
        for (Photoset photoset : api.getPhotosetsInterface().getList(getUserId()).getPhotosets()) {
            if (photoset.getTitle().equals(setName)) {
                return photoset;
            }
        }
        return null;
    }

    private void addToPhotoset(String setName, String photoId) throws FlickrException {
        Photoset set = findByName(setName);
        String setId;
        if (set == null) {
            setId = createSet(setName);
        } else {
            setId = set.getId();
        }
        api.getPhotosetsInterface().addPhoto(setId, photoId);
    }

}
